VNEXT-83184: Redesign checkout coupon UI - #1439
Conversation
Implement combined coupon input states (default, filled, success, error) in DiscountStandalone, add DiscountAppliedBar, and extend enUs discounts strings for GOLF to translate into other locales. Co-authored-by: Cursor <cursoragent@cursor.com>
Versioning can be handled in the release workflow; the coupon redesign does not need a local changeset. Co-authored-by: Cursor <cursoragent@cursor.com>
🦋 Changeset detectedLatest commit: dbf3f0d The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Bump @godaddy/react and @godaddy/localizations so the Version Packages workflow can publish after merge. Co-authored-by: Cursor <cursoragent@cursor.com>
Clarify in DiscountStandalone and DiscountAppliedBar that the redesign cannot reuse the old input/button/chip composition, so those imports were dropped from this path. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the explanation in the PR description and review comments instead. Co-authored-by: Cursor <cursoragent@cursor.com>
abansal2-godaddy
left a comment
There was a problem hiding this comment.
Reviewer notes (also in the PR description): why the layout changed, and why the old discount imports were dropped from — without leaving that rationale in the source files.
| import { eventIds } from '@/tracking/events'; | ||
| import { TrackingEventType, track } from '@/tracking/track'; | ||
| import { Discounts } from './discounts'; | ||
| import type { DiscountFormProps } from './types'; |
There was a problem hiding this comment.
Why these imports changed / why the old ones are gone from this file
Previously this file composed:
DiscountInputDiscountApplyButtonDiscountErrorListDiscounts/DiscountTag
Those matched the old UX (separate input + button, large alert errors, chip tags with code only).
VNEXT-83184 needs a different UX, so those imports were removed from this path:
- Input + Apply (or clear) must live in one bordered row → not standalone
DiscountInput/DiscountApplyButton - Errors are a short helper under the field → not
DiscountErrorList - Success needs code + formatted amount + remove in a full-width bar → not chip
DiscountTags
The old modules are still in the package/exported for now; they just are not used by DiscountStandalone anymore. Cleanup can be a follow-up.
| <div className='flex flex-col gap-1.5'> | ||
| <div | ||
| className={cn( | ||
| 'flex h-14 items-center justify-between rounded-md border bg-white py-2 pl-4 pr-2', | ||
| hasError | ||
| ? 'border-[#EF4444]' | ||
| : isFocused || hasInputValue | ||
| ? 'border-[#2563EB]' | ||
| : 'border-[#D1D5DB]' | ||
| )} |
There was a problem hiding this comment.
Why the layout is inlined here
This combined bordered row (input + Apply, border color by default/filled/error) is the core of the redesign. Wiring the old separate input/button components into this shell would mean rewriting their APIs anyway, so the field markup lives here and keeps the four visual states in one place.
| inputInMinorUnits = true, | ||
| onRemove, | ||
| isRemoving, | ||
| }: DiscountAppliedBarProps) { |
There was a problem hiding this comment.
Why a new DiscountAppliedBar instead of tweaking DiscountTag
DiscountTag is a small chip (tag icon + code + X) and has no amount. The success state in the design is a full-width green bar: check + code + – $amount + remove.
That is a different component shape, so we added this bar for DiscountStandalone rather than overloading the chip. DiscountTag / Discounts remain in the package unused by this path until a cleanup PR.
Reviewer note: layout vs old importsDetails are on the Files changed tab (inline comments) and in the updated PR description. Short version
|
…c intact. Preserve the original code collection and handlers; limit the change to the new coupon UI, amount lookup for the success bar, and error helper copy. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@abansal2-godaddy - is the main goal here to show each coupon codes value instead of a single discount total? I'd prefer not to make huge design changes if possible. We currently follow a similar pattern to other checkouts so I don't think it would be confusing users thinking it's mandatory. |
No @pbennett1-godaddy ,It's more of a UI and experience change only with proper error states and intent when a C1 applies a coupon. |
you can use the nextjs sample app in this repo to test against a dev/test env store. Can you look into what discount GPAs actually return on failure? I don't think we should have a default of "Coupon isn't valid" cause I think there is basically only a single error of "coupon code failed to apply" from the BE. Invalid would lead customers to believe the coupon they tried to use even if there was an error was an invalid code. |
Yes you are right, I'll check what we get as response under various cases from BE and have the error state render the intended failure |

Summary
Implements VNEXT-83184: redesign the checkout coupon / promotion code UI (default → filled → success → error).
Where this lives:
@godaddy/reactDiscountStandalone(used by Bruce whenenablePromotionCodesis on). Copy keys are in@godaddy/localizations(enUsonly; GOLF for other locales).Why a new layout (not a small tweak)
Old UI was four separate pieces wired side-by-side:
DiscountInputDiscountApplyButtonDiscountErrorListDiscounts+DiscountTagNew design from the ticket is a different composition:
That is why markup for the field is inlined in
DiscountStandalone, and applied coupons use a dedicatedDiscountAppliedBar, instead of stretching the old input / button / chip APIs into a shape they were not built for.Why those imports were removed from
DiscountStandaloneThey were removed from this checkout path only because the redesigned states no longer use those components:
DiscountInputInputwrapperDiscountApplyButtonDiscountErrorListDiscounts/DiscountTagFollow-up (not blocking this PR): the old
discount-input,discount-apply-button,discount-error-list,discount-tag, anddiscountsfiles are still in the package and still exported. They are unused byDiscountStandalone. We can delete them or evolve them in place in a cleanup PR once we confirm nothing else imports them.What changed in this PR
discount-standalone.tsx— new combined field + error helper; wires success viaDiscountAppliedBardiscount-applied-bar.tsx— success-state row (code + amount + remove)enUs.ts—haveACouponCode,invalid,removeCoupon@godaddy/react+@godaddy/localizationsJira
https://godaddy-corp.atlassian.net/browse/VNEXT-83184
Test plan